﻿using Blm.VisionCloud.FrameWork.OSS;
using Microsoft.Extensions.Options;
using Minio;
using Minio.DataModel;
using Minio.Exceptions;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
using VisionCloud.Utility;
using VisionCloud.Utility.Security;

namespace VisionCloud.Service.Ms
{
    /// <summary>
    /// Entity for File Request Rewrite
    /// </summary>
    public class FileRequestRewriteEntity
    {
        /// <summary>
        /// is need to Rewite
        /// </summary>
        public bool IsNeedToRewrite { get; set; }

        /// <summary>
        /// File Type for Request
        /// </summary>
        public string RequestFileType { get; set; }

        public string OriginalFilePath { get; set; }
        public string TargetFilePath { get; set; }

        public FileRequestRewriteEntity(string originalFilePath)
        {
            this.OriginalFilePath = originalFilePath;
        }
    }

    public class MSOSSService
    {
        private string minio_server;
        private string minio_accessKey;
        private string minio_secretKey;
        private MinioClient minioClient;

        public MSOSSService()
        {

        }

        public MSOSSService(IOptions<OssSettingOption> options)
        {
            ServicePointManager.ServerCertificateValidationCallback = delegate (object s, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            };
            minio_server = options.Value.Endpoint;
            minio_accessKey = AesCoreHelper.Decrypt(options.Value.AccessKey, AesCoreHelper.Sceret);
            minio_secretKey = AesCoreHelper.Decrypt(options.Value.SecretKey, AesCoreHelper.Sceret);
            minioClient = new MinioClient(minio_server, minio_accessKey, minio_secretKey).WithSSL(options.Value.Secure);
            //查询bucket是否存在
        }

        private async Task<string> getURL(string bucket, string objectName)
        {
            //过期时间是2天
            String url = await minioClient.PresignedGetObjectAsync("task-dotcloud-zip", "蔡工Test111-1栋-1层-初测-结构工程-巡检.zip", 60 * 60 * 24);
            return url;
        }

        private static string[] filterArray = new string[] { "/taskdata/", "/report/", "/log/", "/SystemFiles/", "/taskdotclouddata/" };

        /// <summary>
        /// retrun true if Need ToRewrite Uri
        /// </summary>
        /// <param name="uri">uri path</param>
        /// <returns></returns>
        private void isNeedToRewriteUri(FileRequestRewriteEntity frre)
        {
            var path = frre.OriginalFilePath.ToLower();
            frre.RequestFileType = string.Empty;
            foreach (var item in filterArray)
            {
                if (path.Contains(item))
                {
                    frre.RequestFileType = item;
                    frre.IsNeedToRewrite = true;
                    break;
                }
            }
            if (string.IsNullOrEmpty(frre.RequestFileType))
            {
                frre.IsNeedToRewrite = false;
            }
        }

        public FileRequestRewriteEntity GetObjectRequestURL(string value)
        {
            FileRequestRewriteEntity frre = new FileRequestRewriteEntity(value);
            isNeedToRewriteUri(frre);
            //if (frre.IsNeedToRewrite)
            //{
            //    fileStoreExtend(frre);
            //}
            return frre;
        }

        public async Task<(bool, string)> GetObjectAsync(string bucketName, string objectName, string targetFilePath, ServerSideEncryption sse = null, CancellationToken cancellationToken = default)
        {
            try
            {
                // Check whether the object exists using statObjectAsync().
                // If the object is not found, statObjectAsync() throws an exception,
                // else it means that the object exists.
                // Execution is successful.
                var objectStat = await minioClient.StatObjectAsync("mybucket", "myobject");

                // Gets the object's data and stores it in photo.jpg
                await minioClient.GetObjectAsync(bucketName, objectName, targetFilePath, sse, cancellationToken);
                return (true, string.Empty);
            }
            catch (MinioException e)
            {
                return (false, e.Message);
            }
        }

        public async Task<(bool, string)> GetObjectAsync(string bucketName, string objectName, System.IO.Stream targetStream, ServerSideEncryption sse = null, CancellationToken cancellationToken = default)
        {
            try
            {
                // Check whether the object exists using statObject().
                // If the object is not found, statObject() throws an exception,
                // else it means that the object exists.
                // Execution is successful.
                var objectStat = await minioClient.StatObjectAsync(bucketName, objectName);
                // Get input stream to have content of 'my-objectname' from 'my-bucketname'
                await minioClient.GetObjectAsync(bucketName, objectName,
                                                 (stream) =>
                                                 {
                                                     //  long count = stream.Length;
                                                     stream.CopyTo(targetStream);
                                                 }, sse, cancellationToken);
                return (true, string.Empty);
            }
            catch (MinioException e)
            {
                Console.WriteLine("Error occurred: " + e);
                return (false, e.ToString());
            }
        }

        public async Task<(bool, string)> GetObjectAsync(string bucketName, string objectName, System.IO.Stream targetStream, long offset, long length, ServerSideEncryption sse = null, CancellationToken cancellationToken = default)
        {
            try
            {
                // Check whether the object exists using statObject().
                // If the object is not found, statObject() throws an exception,
                // else it means that the object exists.
                // Execution is successful.
                var objectStat = await minioClient.StatObjectAsync(bucketName, objectName);

                // Get input stream to have content of 'my-objectname' from 'my-bucketname'
                await minioClient.GetObjectAsync(bucketName, objectName, offset, length,
                                                 (stream) =>
                                                 {
                                                     //  long count = stream.Length;
                                                     stream.CopyTo(targetStream);
                                                 }, sse, cancellationToken);
                return (true, string.Empty);
            }
            catch (MinioException e)
            {
                Console.WriteLine("Error occurred: " + e);
                return (false, e.ToString());
            }
        }
    }
}